package com.ctg.sysmgr.sso.server.service.cacheTicket.impl;

import java.util.Collection;
import java.util.Map;

import org.hibernate.annotations.common.util.StringHelper;
import org.jasig.cas.authentication.principal.Service;
import org.jasig.cas.ticket.ServiceTicket;
import org.jasig.cas.ticket.Ticket;
import org.jasig.cas.ticket.TicketGrantingTicket;
import org.jasig.cas.ticket.registry.AbstractDistributedTicketRegistry;

import com.ctg.itrdc.cache.core.CacheService;
import com.ctg.sysmgr.sso.server.common.uitl.SerializeUtil;
import com.ctg.sysmgr.sso.server.service.cacheTicket.IRedisTicketRegistry;

public class RedisTicketRegistry extends AbstractDistributedTicketRegistry implements IRedisTicketRegistry  {

	
	private String groupId ;
	private CacheService cacheService;
	//超时时间
	private Integer timeOutOfTGT;
	private Integer timeOutOfST;
	
	private String successOfSet;//调用set接口成功返回标志 0
	private Long successOfExpire;//调用expire接口成功返回标志 1

	
	public String getSuccessOfSet() {
		return successOfSet;
	}

	public void setSuccessOfSet(String successOfSet) {
		this.successOfSet = successOfSet;
	}

	public Long getSuccessOfExpire() {
		return successOfExpire;
	}

	public void setSuccessOfExpire(Long successOfExpire) {
		this.successOfExpire = successOfExpire;
	}

	public  RedisTicketRegistry(CacheService cacheService,
		String groupId,Integer timeOutOfTGT,Integer timeOutOfST) {
		
		
		if(StringHelper.isEmpty(groupId) || timeOutOfST == null || timeOutOfTGT == null){
			throw new RuntimeException("初始化redis服务参数为空");
		}
		
		
		//初始化时，设置超时时间
		this.groupId = groupId;
		this.cacheService =cacheService;
		this.timeOutOfST = timeOutOfST;
		this.timeOutOfTGT = timeOutOfTGT;
	}
	
	/**
	 * 将ticket放到缓存中，以支持分布式
	 */
	@Override
	public void addTicket(Ticket ticket) {
		byte[] bytes = SerializeUtil.serialize(ticket);//序列化对象
		if(ticket == null){
			return ;
		}
		String result = cacheService.set(groupId, ticket.getId(), bytes);//放入缓存串
		if(successOfSet.equals(result)){
			//设置超时时间
			Long res = cacheService.expire(groupId, ticket.getId(), getTimeout(ticket));
			if(successOfExpire.equals(res)){//long类型的比较-128--127可用==比较，其余用==的比较的话，将会是以对象的方式来比较
				logger.info("添加ticket到缓存成功,{}",ticket);
			}else{
				logger.info("添加ticket到缓存成功，但是设置其超时时间失败,{}",ticket);
			}
			
		}else{
			logger.error("添加ticket到缓存失败,",ticket);
		}
	}

	@Override
	public Ticket getTicket(String ticketId) {
		if (ticketId == null) {
            return null;
        }
        logger.info("获取ticket中,ticketId="+ticketId);
        byte[] bytes = cacheService.getBytes(groupId,ticketId);
        //if bytes is null ,don't need execute the rest 
        if(bytes == null){
        	return null;
        }
        Ticket ticket = (Ticket) SerializeUtil.unserialize(bytes);
        ticket = getProxiedTicketInstance(ticket);//转换ticket，使tgt添加st的时候能够更新到redis缓存中
        if (ticket != null) {
            logger.info("获取ticket成功,ticketId="+ticketId);
        }else{
        	logger.info("获取ticket失败,ticketId="+ticketId);
        }
        return ticket;
	}

	@Override
	public boolean deleteTicket(String ticketId) {
		 if (ticketId == null) {
	            return false;
	        }

	        final Ticket ticket = getTicket(ticketId);
	        if (ticket == null) {
	            return false;
	        }

	        if (ticket instanceof TicketGrantingTicket) {
	            logger.info("删除ticket之前先删除它的service ticket");
	            deleteChildren((TicketGrantingTicket) ticket);
	        }
	        try {
	            Long result = cacheService.del(groupId,ticketId);
	            if(result > 0){
	            	return true;
	            }else{
	            	return false;
	            }
	        } catch (final Exception e) {
	            logger.error("Failed deleting {}", ticketId, e);
	        }
	        return false;
	}

	@Override
	public Collection<Ticket> getTickets() {
		
		throw new UnsupportedOperationException("GetTickets not supported.");
	}

	
	/**
     * Delete TGT's service tickets.
     *
     * @param ticket the ticket
     */
    private void deleteChildren(final TicketGrantingTicket ticket) {
        // delete service tickets
        final Map<String, Service> services = ticket.getServices();
        if (services != null && !services.isEmpty()) {
            for (final Map.Entry<String, Service> entry : services.entrySet()) {
                if (cacheService.del(groupId,entry.getKey()) > 0) {
                    logger.trace("Removed service ticket [{}]", entry.getKey());
                } else {
                    logger.trace("Unable to remove service ticket [{}]", entry.getKey());
                }
            }
        }
    }
    
//  CAS缓存没有覆盖这两个方法
//	@Override
//    public int sessionCount() {
//        int count = 0;
////        for (final Ticket t : this.cache.values()) {
////            if (t instanceof TicketGrantingTicket) {
////                count++;
////            }
////        }
//        return count;
//    }
//
//    @Override
//    public int serviceTicketCount() {
//        int count = 0;
////        for (final Ticket t : this.cache.values()) {
////            if (t instanceof ServiceTicket) {
////                count++;
////            }
////        }
//        return count;
//    }

	@Override
	protected void updateTicket(Ticket ticket) {
		logger.info("Updating ticket {}", ticket);
		byte[] bytes = SerializeUtil.serialize(ticket);//序列化对象
		String result = cacheService.set(groupId, ticket.getId(), bytes);//替换
		if(successOfSet.equals(result)){
			//重新设置超时时间
			Long res = cacheService.expire(groupId, ticket.getId(), getTimeout(ticket));
			if(successOfExpire.equals(res)){//long类型的比较-128--127可用==比较，其余用==的比较的话，将会是以对象的方式来比较
				logger.info("更新ticket,{}",ticket);
			}else{
				logger.info("更新ticket成功，但是设置其超时时间失败,{}",ticket);
			}
		}else{
			logger.error("Failed updating {}", ticket);
		}
		
	}

	
	
	/**
     * 关闭缓存
     *
     * @throws Exception the exception
     */
    public void destroy() throws Exception {
        
    }
    
    
	@Override
	protected boolean needsCallback() {
		 return true;
	}
	
	  /**
     * Gets the timeout value for the ticket.
     *
     * @param t the t
     * @return the timeout
     */
    private int getTimeout(final Ticket t) {
        if (t instanceof TicketGrantingTicket) {
            return this.timeOutOfTGT;
        } else if (t instanceof ServiceTicket) {
            return this.timeOutOfST;
        }
        throw new IllegalArgumentException("Invalid ticket type");
    }
}
